import os
import sys
import logging
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.abspath(os.path.dirname(curPath) + os.path.sep + ".")
sys.path.append(rootPath)
sys.path.append(os.path.join(rootPath,'commDriver'))
sys.path.append(os.path.join(rootPath,'data'))
logging.info(sys.path)
logging.info(sys.path)

from commDriver.TS_CAN import *
import pytest
from pytest_assume.plugin import assume
import crcmod
import math
from eprogress import LineProgress
from threading import Thread
import hashlib
import xml.etree.ElementTree as ET
import zipfile
import shutil
import Set_up

class Download(Thread):
    def __init__(self,candriver,diag,zip_path,erash_startaddress,erash_size,exit=False,crcerror=False,
                    skipprecheck=False,skipflash=False,skipapp=False,skipboot=False,errorApp=False,errorBoot=False,skiprestart = False,isContinue = True):
        Thread.__init__(self)
        self.candriver = candriver          #can引用
        self.diag = diag                    #诊断引用--物理寻址
        # self.diagfun = diagfun              #诊断引用--功能寻址
        self.zip_path = zip_path            #BYD-zip文件路径
        self.eras_startaddress=erash_startaddress           #31服务擦除起始地址
        self.erash_size=erash_size          #31服务擦除地址大小
        self.startaddress=0x0               #bin文件刷写起始地址
        self.size=0x0                       #bin文件刷写大小
        self.stop_flag=False                #外部条件停止刷写过程
        self.progress_number = 0            #刷写进度条
        self.md5_state = False              #MD5文件读取比对正常标志
        self.app = False                    #app/flash选择
        self.normal = False                 #刷写异常后能否正常开机
        self.erashing = False               #正在擦除内存标志
        self.exit = exit                    #退出当前boot模式
        self.crcerror=crcerror              #crc校验错误
        self.skipprecheck=skipprecheck      #跳过预刷写条件检测
        self.skipflash=skipflash            #跳过Flash Driver下载
        self.skipRestart = skiprestart      #跳过重启
        self.isContinue = isContinue        #是否继续流程
        self.finish = False                 #刷写完成

        '''刷写结果标志'''
        self.success_flag = False           #刷写成功标志
        self.transmit_flag = True          #数据传输标志
        self.eraseMemory_flag = True       #擦除内存标志
        self.dependencies_flag =True       #软件一致性检查标志
        self.restart_flag = True           #重启状态标志
        self.app_crc_flag = True               #crc校验状态标志
        self.boot_crc_flag = True               #crc校验状态标志

        self.AppSize = 0
        self.BootSize = 0
        self.skipapp=skipapp
        self.skipboot=skipboot
        self.errorApp = errorApp
        self.errorBoot = errorBoot
        self.start()

    def get_path(self):
        root = os.path.abspath(os.path.dirname(__file__))
        dirpath = os.path.join(root,r'temp')
        zFile = zipfile.ZipFile(self.zip_path, "r")
        self.app_filepath = ''
        self.app_filename = ''
        self.flash_filepath = ''
        self.flash_filename = ''
        self.xml_filepath = ''
        self.xml_filename = ''
        self.boot_name = ''
        self.boot_filepath = ''
        for fileM in zFile.namelist(): 
            zFile.extract(fileM, dirpath)
            if 'app' in fileM.lower():
                self.app_filename=fileM
                self.app_filepath = os.path.join(dirpath,fileM)
            elif 'flash' in fileM.lower():
                self.flash_filename=fileM
                self.flash_filepath = os.path.join(dirpath,fileM)
            elif 'xml' in fileM.lower():
                self.xml_filename=fileM
                self.xml_filepath = os.path.join(dirpath,fileM)
            elif 'boot' in fileM.lower():
                self.boot_name=fileM
                self.boot_filepath = os.path.join(dirpath,fileM)
            else:
                pass

        zFile.close()
        return self.app_filepath,self.flash_filepath,self.xml_filepath,self.boot_filepath

    def get_xml_md5(self):
        tree = ET.parse(self.xml_filepath)
        root = tree.getroot()
        nodes = root.findall('MD5')
        xml_md5 = {}
        for node in nodes:
            xml_md5[node.attrib['FileName']] = node.text
        return xml_md5

    def get_file_md5(self,path_hex):
        with open(path_hex, 'rb') as file:
            data = file.read()
        diff_check = hashlib.md5()
        diff_check.update(data)
        md5_code = diff_check.hexdigest()
        return md5_code.upper()

    def check_md5(self):
        logging.info(self.app_filepath)
        app_md5 = self.get_file_md5(self.app_filepath)
        flash_md5 = self.get_file_md5(self.flash_filepath)
        md5_dict = self.get_xml_md5()
        xml_app_md5 = md5_dict[self.app_filename].upper()
        xml_flash_md5 = md5_dict[self.flash_filename].upper()
        logging.info('Config xml read md5 is: {}'.format(md5_dict))
        logging.info('hex file read app_md5 is: {}'.format(app_md5))
        logging.info('hex file read flash_md5 is: {}'.format(flash_md5))
        if (xml_app_md5 == app_md5)and(xml_flash_md5 == flash_md5):
            self.md5_state = True
        return self.md5_state

    def parse_file(self,file_path):
        self.file_type = os.path.splitext(file_path)[-1]
        self.binfile_handle = bincopy.BinFile()
        if(self.file_type == '.hex' or self.file_type == '.HEX'):
            with open(file_path, 'r') as fin:
                self.binfile_handle.add_ihex(fin.read())
            self.size = self.binfile_handle.segments.maximum_address - self.binfile_handle.segments.minimum_address
        if(self.file_type == '.bin' or self.file_type == '.BIN'):
            with open(file_path, 'rb') as fin:
                self.binfile_handle.add_binary(fin.read())
        if(self.file_type == '.s19'):
            with open(file_path, 'r') as fin:
                self.binfile_handle.add_srec(fin.read())
        # logging.info(binfile_handle.segments())  #All data

        
        return self.binfile_handle.segments

    def download(self,path):
        download_data=[]
        self.parse_file(path)
        for index,segment in enumerate(self.binfile_handle.segments):
            if(self.file_type == '.bin' or self.file_type == '.BIN'):
                start_address = self.startaddress
                segment_size = self.size
            else:
                start_address = segment.minimum_address
                segment_size = segment.maximum_address - segment.minimum_address

                
            # 34 Server,Request download
            Request_download_CMD = [0x34,00,0x44] + \
                                    [(start_address>>24) & 0xFF] + [(start_address>>16) & 0xFF] + [(start_address>>8) & 0xFF] + [(start_address) & 0xFF] +\
                                    [(segment_size>>24) & 0xFF] + [(segment_size>>16) & 0xFF] + [(segment_size>>8) & 0xFF] + [(segment_size) & 0xFF]
            rep_value,rep_size = self.diag.req_and_res_can(Request_download_CMD,len(Request_download_CMD),enable_print= False)

            if rep_value[0:1] == [0x74]:
                lengthformatidentifier = rep_value[1]
                maxnumberofblocklength = rep_value[2]*256+rep_value[3]
                # 36 Server, start download
                if maxnumberofblocklength<0xfff:
                    numberofblockdatalength = maxnumberofblocklength-2
                    data_36_send_times = math.ceil(segment_size/numberofblockdatalength)
                    print('data_36 send times is: ',data_36_send_times)
                    # line progress
                    line_progress = LineProgress(title='upgrade progress')
                    try:
                        for i in range(data_36_send_times):
                            self.progress_number = ((i+1)/data_36_send_times)*100
                            line_progress.update(self.progress_number)
                            blocksequencecounter = (i+1)%256
                            if i == (data_36_send_times - 1):
                                download_data_CMD = [0x36,blocksequencecounter]+list(segment.data)[i*numberofblockdatalength:]
                            else:
                                download_data_CMD = [0x36,blocksequencecounter]+list(segment.data)[i*numberofblockdatalength:((i+1)*numberofblockdatalength)]
                            rep_value,rep_size = self.diag.req_and_res_can(download_data_CMD,len(download_data_CMD),enable_print= False)
                            # logging.info('i is: {}, rep_value is: {}, flag is: {}'.format(i,rep_value,self.stop_flag))
                            if rep_value[0:1] != [0x76] or self.stop_flag == True :
                                self.transmit_flag = False
                                raise Exception('download termination')

                    except Exception as e:
                        logging.info(e)
            else:
                self.transmit_flag = False
                logging.info('34 Server negative response!')
            # 37 Server, stop download
            download_data = download_data + list(segment.data)
            try:
                rep_value,rep_size = self.diag.req_and_res_can([0x37],1,enable_print= False)
                if rep_value[0:1] == [0x77]:
                    logging.info('Block {} upgrade success!'.format(index))
                else:
                    logging.info('37 server negative response!')
            except:
                logging.info('37 server no response!')
        crc_32=crcmod.predefined.mkCrcFun('crc-32')
        download_data_byte = bytearray(download_data)
        crc_value = binascii.crc32(download_data_byte)
        return crc_value

    def seedkey(self,seed):
        KeyKValue = 0x0094
        key = [0,0,0,0]

        iSeed = seed[0] << 24|seed[1] << 16|seed[2] << 8 |seed[3]
        KeyResult = ((((iSeed >> 1) ^ iSeed) << 3) ^ (iSeed >> 2))
        STccKey = KeyResult ^ KeyKValue
        key[0] = ((STccKey)>>24) & 0xFF
        key[1] = ((STccKey)>>16) & 0xFF
        key[2] = ((STccKey)>>8) & 0xFF
        key[3] = (STccKey) & 0xFF
        return key

    def pre_update(self):
        try:
            '''预刷新步骤'''
            #step1: 扩展会话模式  
            # 
            uds_rep,datasize = self.diag.req_and_res_can([0x10,0x01],2)
            time.sleep(12)          
            uds_rep,datasize = self.diag.req_and_res_can([0x10,0x03],2)
            if uds_rep[0:2] == [0x50,0x03]:
                logging.info('Enter extended session ok')
            else:
                logging.info('Enter extended session fail')
                return
            #step3: 检查预刷新条件
            if self.skipprecheck == False:
                uds_rep,datasize = self.diag.req_and_res_can([0x31,0x01,0x02,0x03],4)
                if uds_rep[0:5] == [0x71,0x01,0x02,0x03,0x00]:
                    logging.info('Check programming precondition ok')
                else:
                    logging.info('Check programming precondition fail')
                #step7: 安全算法          
                uds_rep,datasize = self.diag.req_and_res_can([0x27,0x01],2)
                if uds_rep[0:2] == [0x67,0x01]:
                    logging.info('Request seed ok')
                else:
                    logging.info('Request seed fail')
                seed = uds_rep[2:6]
                key = self.seedkey(seed)
                uds_rep,datasize = self.diag.req_and_res_can([0x27,0x02]+key,6)
                if uds_rep[0:2] == [0x67,0x02]:
                    logging.info('Send key level1 ok')
                else:
                    logging.info('Send key level1 fail')
                # #step5: 停止诊断服务
                # uds_rep,datasize = self.diagfun.req_and_res_can([0x85,0x82],2)
                # #step6: 通信使能接受，关闭发送
                # uds_rep,datasize = self.diagfun.req_and_res_can([0x28,0x11,0x01],3)
                #step8: 编程会话模式
                uds_rep,datasize = self.diag.req_and_res_can([0x10,0x02],2)
                if uds_rep[0:2] == [0x50,0x02]:
                    logging.info('Enter programming session ok')
                else:
                    logging.info('Enter programming session fail')
                #step9: 安全算法
                uds_rep,datasize = self.diag.req_and_res_can([0x27,0x01],2)
                if uds_rep[0:2] == [0x67,0x01]:
                    logging.info('Request seed ok')
                else:
                    logging.info('Request seed fail')
                seed = uds_rep[2:6]
                key = self.seedkey(seed)
                uds_rep,datasize = self.diag.req_and_res_can([0x27,0x02]+key,6)
                if uds_rep[0:2] == [0x67,0x02]:
                    logging.info('Send key level1 ok')
                else:
                    logging.info('Send key level1 fail')
                if self.exit:
                    #step9-1: 退出boot模式
                    uds_rep,datasize = self.diag.req_and_res_can([0x10,0x01],2)
                    if uds_rep[0:2] == [0x50,0x01]:
                        logging.info('Exit programming session ok')
                    else:
                        logging.info('Exit programming session fail')
            else:
                logging.info('Berfor update, CAN Communication Error!')
        except:
            logging.info('Berfor update, CAN Communication Error!')

    def getFile(self,filepath):
        segments = self.parse_file(filepath)
        if(self.file_type == '.bin' or self.file_type == '.BIN'):
                start_address = self.startaddress
                segment_size = self.size
        else:
            start_address = segments.minimum_address
            segment_size = segments.maximum_address - segments.minimum_address
        return start_address, segment_size

    def flash_driver_update(self):

        logging.info('---------------------------------Starting update flash driver---------------------------------')
        #step:10/11/12: 34、36、37服务更新flash Drive   
        check_crc_flash = self.download(self.flash_filepath)   
        #step13: 检查传输行列
        crc_flash=[0,0,0,0]
        crc_flash[0] = ((check_crc_flash)>>24) & 0xFF
        crc_flash[1] = ((check_crc_flash)>>16) & 0xFF
        crc_flash[2] = ((check_crc_flash)>>8) & 0xFF
        crc_flash[3] = (check_crc_flash) & 0xFF
        try:
            uds_rep,datasize = self.diag.req_and_res_can([0x31,0x01,0x02,0x02]+crc_flash,8)
            if uds_rep[0:5] == [0x71,0x01,0x02,0x02,0x00]:
                logging.info('Check Flash transmit sequence ok')
            else:
                logging.info('Check Flash transmit sequence fail')
        except:
            logging.info('31 server check Flash transmit sequence no response!')

    def app_update(self):
        logging.info('---------------------------------Starting update App---------------------------------')
        self.app = True
        '''内存擦除前'''
        time.sleep(0.5)
        #step14: 擦除存储器程序
        self.erashing = True
        time.sleep(0.1)
        '''内存擦除中'''
        try:
            if self.errorApp == True:
                self.app_filepath = Set_up.errorApp_path

            startaddress, size = self.getFile(self.app_filepath)
            eras_startaddress = [0x00,0x00,0x00,0x00]
            eras_startaddress[0] = ((startaddress)>>24) & 0xFF
            eras_startaddress[1] = ((startaddress)>>16) & 0xFF
            eras_startaddress[2] = ((startaddress)>>8) & 0xFF
            eras_startaddress[3] = (startaddress) & 0xFF
            erash_size = [0x00,0x00,0x00,0x00]
            erash_size[0] = ((size)>>24) & 0xFF
            erash_size[1] = ((size)>>16) & 0xFF
            erash_size[2] = ((size)>>8) & 0xFF
            erash_size[3] = (size) & 0xFF


            uds_rep,_ = self.diag.req_and_res_can([0x31,0x01,0xFF,0x00,0x44]+eras_startaddress+ erash_size,13)
            if uds_rep[0:5] == [0x71,0x01,0xFF,0x00,0x00]:
                self.eraseMemory_flag = True
                logging.info('Erase Memory ok')
            else:
                self.eraseMemory_flag = False
                logging.info('Erase Memory fail')
                return
        except:
            logging.info('Erase Memory no response!')
        time.sleep(1)
        #step15/16/17: 34、36、37服务下载程序
        self.erashing = False
        check_crc_app = self.download(self.app_filepath) 
        if self.isContinue:
            #step18: 检查传输行列
            if self.crcerror:
                crc_app=[0,0,0,0]
            else:
                crc_app=[0,0,0,0]
                crc_app[0] = ((check_crc_app)>>24) & 0xFF
                crc_app[1] = ((check_crc_app)>>16) & 0xFF
                crc_app[2] = ((check_crc_app)>>8) & 0xFF
                crc_app[3] = (check_crc_app) & 0xFF
            try:
                # uds_rep,datasize = self.diag.req_and_res_can([0x3E,0x80],2)
                uds_rep,datasize = self.diag.req_and_res_can([0x31,0x01,0x02,0x02]+crc_app,8)
                if uds_rep[0:5] == [0x71,0x01,0x02,0x02,0x00]:
                    self.app_crc_flag = True
                    logging.info('Check APP transmit sequence ok')
                else:
                    self.app_crc_flag = False
                    logging.info('Check APP transmit sequence fail')
                    # logging.info('crc value is response: '.format(hex(crc_app)))
                    # logging.info('31 response: '.format(hex(uds_rep)))   
            except:
                logging.info('Check APP transmit and programming Dependencies no response!')
                self.finish = False                

    def boot_update(self):
        logging.info('---------------------------------Starting update boot---------------------------------')
        if self.boot_name != '':
            self.app = True
            '''内存擦除前'''
            time.sleep(1)
            #step14: 擦除存储器程序
            self.erashing = True
            time.sleep(0.5)
            '''内存擦除中'''
            try:
                if self.errorBoot == True:
                    self.boot_filepath = Set_up.errorBoot_path

                startaddress, size = self.getFile(self.boot_filepath)
                eras_startaddress = [0x00,0x00,0x00,0x00]
                eras_startaddress[0] = ((startaddress)>>24) & 0xFF
                eras_startaddress[1] = ((startaddress)>>16) & 0xFF
                eras_startaddress[2] = ((startaddress)>>8) & 0xFF
                eras_startaddress[3] = (startaddress) & 0xFF
                erash_size = [0x00,0x00,0x00,0x00]
                erash_size[0] = ((size)>>24) & 0xFF
                erash_size[1] = ((size)>>16) & 0xFF
                erash_size[2] = ((size)>>8) & 0xFF
                erash_size[3] = (size) & 0xFF
                uds_rep,_ = self.diag.req_and_res_can([0x31,0x01,0xFF,0x00,0x44]+eras_startaddress + erash_size,13)
                if uds_rep[0:5] == [0x71,0x01,0xFF,0x00,0x00]:
                    self.eraseMemory_flag = True
                    logging.info('Erase Memory ok')
                else:
                    self.eraseMemory_flag = False
                    logging.info('Erase Memory fail')
            except:
                logging.info('Erase Memory no response!')
            time.sleep(1)
            #step15/16/17: 34、36、37服务下载程序
            self.erashing = False
            check_crc_app = self.download(self.boot_filepath) 

            if self.isContinue:
                #step18: 检查传输行列
                if self.crcerror:
                    crc_app=[0,0,0,0]
                else:
                    crc_app=[0,0,0,0]
                    crc_app[0] = ((check_crc_app)>>24) & 0xFF
                    crc_app[1] = ((check_crc_app)>>16) & 0xFF
                    crc_app[2] = ((check_crc_app)>>8) & 0xFF
                    crc_app[3] = (check_crc_app) & 0xFF
                try:
                    # uds_rep,datasize = self.diagfun.req_and_res_can([0x3E,0x80],2)
                    uds_rep,datasize = self.diag.req_and_res_can([0x31,0x01,0x02,0x02]+crc_app,8)
                    if uds_rep[0:5] == [0x71,0x01,0x02,0x02,0x00]:
                        self.boot_crc_flag = True
                        logging.info('Check boot transmit sequence ok')
                    else:
                        self.boot_crc_flag = False
                        logging.info('Check boot transmit sequence fail')    
                except:
                    logging.info('Check boot transmit and programming Dependencies no response!')
                    self.finish = True                
            
    def post_update(self):
        try:
            if self.isContinue:
                #step20: 检查软硬件一致性
                uds_rep,datasize = self.diag.req_and_res_can([0x31,0x01,0xFF,0x01],4)
                if uds_rep[0:5] == [0x71,0x01,0xFF,0x01,0x00]:
                    self.dependencies_flag = True
                    self.finish = True 
                    logging.info('Check programming Dependencies ok')
                else:
                    self.dependencies_flag = False
                    self.finish = False 
                    logging.info('Check programming Dependencies fail')
                #step21: 硬件重启
                if self.skipRestart == False:
                    uds_rep,datasize = self.diag.req_and_res_can([0x11,0x01],2)
                    if uds_rep[0:2] == [0x51,0x01]:
                        self.restart_flag = True 
                        logging.info('Hardware reset ok') 
                    else:
                        self.restart_flag = False
                        logging.info('Hardware reset fail')

                time.sleep(2)
                '''后刷新步骤'''
                #step22: 恢复通信
                uds_rep,datasize = self.diag.req_and_res_can([0x28,0x80,0x01],3)
                #step16-3: 开启DTC 
                uds_rep,datasize = self.diag.req_and_res_can([0x85,0x81],2)

                if self.transmit_flag == True and self.restart_flag == True and self.transmit_flag == True and self.eraseMemory_flag == True \
                        and self.dependencies_flag == True and self.app_crc_flag == True and self.boot_crc_flag == True:
                    self.success_flag = True
                else:
                    self.success_flag = False

        except:
            self.success_flag = False
            self.finish = False 
            logging.info('After update, CAN Communication Error!')

    def post_abnormal_termination_startup(self):            #刷写失败后验证能否正常启动,并判断软件版本 boot版本，DTC是否正常
        for i in range(25):
            uds_rep,datasize = self.diag.req_and_res_can([0x10,0x01],2)
            if len(uds_rep) < 2:
                self.normal =False
            if uds_rep[0:2] == [0x50,0x01]:
                self.normal = True
                break
            else:
                self.normal = False
            time.sleep(0.5)

        '''判断APP版本'''
        for i in range(6):
            uds_rep,datasize = self.diag.req_and_res_can([0x22,0xF1,0x95],3)
            if len(uds_rep) > 2:
                break
            time.sleep(0.5)
        if uds_rep[0:] == [0x62,0xF1,0x95] + Set_up.ECUSoftwareVersionNumber:
            appNumber = True
        else:
            appNumber = False

        '''判断BOOT版本'''
        for i in range(6):
            uds_rep,datasize = self.diag.req_and_res_can([0x22,0xF1,0x80],3)
            if len(uds_rep) > 2:
                break
            time.sleep(0.5)
        if uds_rep[0:] == Set_up.VehicleManufacturerECUBootSoftwareVersionNumber:
            bootNumber = True
        else:
            bootNumber = False

        '''判断初始故障'''
        time.sleep(3)
        uds_rep,datasize = self.diag.req_and_res_can([0x14,0xFF,0xFF,0xFF],4)
        uds_rep,datasize = self.diag.req_and_res_can([0x19,0x02,0x09],3)
        dtc = self.delInitialFailure(uds_rep)
        if dtc == True and appNumber == True and bootNumber == True:
            self.normal = True
        else:
            logging.error('bootNumber:[{0}]--appNumber:[{1}]--dtc:[{2}]'.format(bootNumber, appNumber, dtc))
            self.normal = False

        
    '''判断除了三个初始故障是否有新的故障产生'''
    def delInitialFailure(self,data):
        for i in range(len(Set_up.InitialFailure)):
            if set(Set_up.InitialFailure[i]) < set(data):
                for j in range(len(Set_up.InitialFailure[i])):
                    data.remove(Set_up.InitialFailure[i][j])
        if data != [0x59,0x02,0x09]:
            actuRespStr = binascii.b2a_hex(bytearray(data[3:]), ' ') 
            logging.error('response:[{0}]'.format(actuRespStr))
            return False 
        else:
            return True

    def run(self):
        self.get_path()
        state = self.check_md5()
        if state:
            self.pre_update()
            if self.skipflash == False:
                self.flash_driver_update()

            if self.skipapp == False:
                self.app_update()
            if self.skipboot == False:
                self.boot_update()
            self.post_update()
        else:
            logging.info('MD5 Check fail!')
        try:
            (dirpath,filename) = os.path.split(self.flash_filepath)
            shutil.rmtree(dirpath)
        except:
            logging.info('Delete flash file Error!')
        # self.stop_flag=False                #外部条件停止刷写过程
        # self.md5_state = False              #MD5文件读取比对正常标志
        # self.success_flag = False           #刷写成功标志
        # self.app = False                    #app/flash选择
        # self.normal = False                 #刷写异常后能否正常开机
        # self.erashing = False               #正在擦除内存标志

    def set_stop(self,flag):
        if self.app:
            self.stop_flag = flag

if __name__ == '__main__':
    drive_type = 'USE_TS_TC1014_DEVICE'
    configure_baudrate = {'CAN_Type':'CANFD','ArbRate':500,'DataRate':2000,'TermResistor':True}
    '''初始化CAN'''
    project_rbs = TSCAN(drive_type,configure_baudrate)
    project_rbs.connect_application()
    diag = TSCAN_UDS(ASupportFD= 1, AMaxdlc=15, reqID=0x7F2,resID=0x7FA,AFctID=0x7DF,p2_timeout=4000)

    '''选择刷写文件，判断条件，刷写'''
    path = r'F:\BYD\SW\CTLRR-220P_App_4.00.06_Boot_1.5_CT_2.12.2.11_2.1.1.6\byd\App_4.00.06_Boot_1.5_CT_2.12.2.11_2.1.1.6.XCDII.zip'

    erash_startaddress = [0x00,0x05,0x00,0x00]
    erash_size = [0x00,0x08,0x4A,0x96]
    dl = Download(project_rbs,diag,path,erash_startaddress,erash_size)
    # time.sleep(20)
    # logging.info(dl.progress_number)
    # dl.set_stop(True)
    dl.join()

    '''关闭CAN'''
    project_rbs.dis_connect_application()
    diag.UDS_can_delete()